
package ploy.compiler;

import java.util.*;

import org.objectweb.asm.*;
import org.objectweb.asm.util.*;
import org.objectweb.asm.commons.*;

import ploy.lang.*;

/**
 * An abstract syntax tree node representing a function application.
 */
class App extends AST {

    private AST fun;
    private List<AST> args;

    /**
     * Default contructor.
     *
     */
    public App(AST f, List<AST> a) {
	fun = f;
	args = a;
    }

    /**
     * Generate a string representation of the application.
     */
    public String toString( ) {
	String toReturn = "(" + fun.toString();
	Iterator<AST> i = args.iterator();
	while ( i.hasNext() ) {
	    toReturn += " " + i.next().toString();
	}
	toReturn += ")";
	return toReturn;
    }

    /** 
     * The free variables of a function application are the union of
     * the free variables of its function part and application part.
     */
    protected TreeSet<Symbol> calculateFreeVars( ) {
	TreeSet<Symbol> s = (TreeSet<Symbol>)fun.freeVars().clone();
	Iterator<AST> i = args.iterator();
	while ( i.hasNext() ) {
	    s.addAll( i.next().freeVars() );
	}
	return s;
    }

    /** 
     * The lambdas of a function application are the union of
     * the lambdas of its function part and application part.
     */
    public TreeSet<Lambda> allLambdas( ) {
	TreeSet<Lambda> s = 
	    (TreeSet<Lambda>)fun.allLambdas( ).clone(); /* necessary? */
	Iterator<AST> i = args.iterator();
	while ( i.hasNext() ) {
	    s.addAll( i.next().allLambdas() );
	}
	return s;
    }
    
    /** 
     * Generate bytecode of the invocation.  This generates bytecode for 
     * the function part, the application part, and generates an "invoke"
     * instruction.
     */
    public FrameSize generateBytecode( MethodVisitor mv ) {
        FrameSize funMaxS = fun.generateBytecode( mv );
	FrameSize maxFS = funMaxS;
	int curStackSize = 1;
	
	Iterator<AST> i = args.iterator();
	while ( i.hasNext() ) {
	    FrameSize argMaxS = 
		i.next().generateBytecode( mv ).addS( curStackSize );
	    maxFS = FrameSize.max( argMaxS, maxFS );
	    curStackSize++;
	}
	String invokeName = Lambda.invokeName( args.size() );
	String invokeType = Lambda.invokeType( args.size() );
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, DynamicObject.jvmClass, 
                           invokeName, invokeType );
        return maxFS;
    }

    /** 
     * Locating the variables of an application involves simply locating
     * the variables of the function part and the application part.
     */
    public void locateVariables( VarLocationTable t ) {
	fun.locateVariables( t );
	Iterator<AST> i = args.iterator();
	while ( i.hasNext() ) {
	    i.next().locateVariables( t );
	}
    }
    


}